﻿#include "xscalechart_p.h"

XScaleChartPrivate::XScaleChartPrivate()
    : XScalePrivate(),
      scaleChartTitle("Title"),
      scaleChartTitleColor(Qt::black),
      scaleChartTitleEnable(true),
      scaleChartBarBorderColor(Qt::black),
      scaleChartBarBgColor(Qt::white),
      scaleChartBarColor(Qt::green),
      scaleChartBarWarningColor(Qt::red),
      warningValue(maximumRange),
      currentValue(minimumRange),
      currentValueStringColor(Qt::black),
      currentValueShowEnable(true)
{
    titleWidth = 0;
    titleHeight = 0;
    titlePoint = QPointF(0, 0);
    currentValueString = "";
    currentValueStringWidth = 0;
    currentValueStringHeight = 0;
    currentValueStringPonit = QPointF(0, 0);
    barThickness = 0;
    barLength = 0;
}

XScaleChartPrivate::~XScaleChartPrivate()
{

}

XScaleChart::XScaleChart(QWidget *parent, Qt::WindowFlags f)
    : XScale(parent, f),
      xScalePrivateP(new XScaleChartPrivate)
{

}

XScaleChart::~XScaleChart()
{

}

/*!
    \property XScale::scaleChartTitle
    \brief the title of the scaleChart

    The default scaleChartTitle is "Title".

    \sa indent
*/
QString XScaleChart::getScaleChartTitle() const
{
    return xScalePrivateP->scaleChartTitle;
}

void XScaleChart::setScaleChartTitle(const QString string)
{
    if(xScalePrivateP->scaleChartTitle == string)
        return;

    xScalePrivateP->scaleChartTitle = string;
    this->update();
}

/*!
    \property XScale::scaleChartTitleColor
    \brief the color of the scaleChartTitle

    The default scaleChartTitleColor is Qt::black.

    \sa indent
*/
QColor XScaleChart::getScaleChartTitleColor() const
{
    return xScalePrivateP->scaleChartTitleColor;
}

void XScaleChart::setScaleChartTitleColor(const QColor &color)
{
    if(xScalePrivateP->scaleChartTitleColor == color)
        return;

    xScalePrivateP->scaleChartTitleColor = color;
    this->update();
}

/*!
    \property XScale::scaleChartTitleEnable
    \brief the enable of the scaleChartTitle

    The default scaleChartTitleEnable is true.

    \sa indent
*/
bool XScaleChart::getScaleChartTitleEnable() const
{
    return xScalePrivateP->scaleChartTitleEnable;
}

void XScaleChart::setScaleChartTitleEnable(bool enable)
{
    if(xScalePrivateP->scaleChartTitleEnable == enable)
        return;

    xScalePrivateP->scaleChartTitleEnable = enable;
    this->update();
}

/*!
    \property XScale::scaleChartBarBorderColor
    \brief the color of the scaleChartBarBorder

    The default scaleChartBarBorderColor is Qt::black.

    \sa indent
*/
QColor XScaleChart::getScaleChartBarBorderColor() const
{
    return xScalePrivateP->scaleChartBarBorderColor;
}

void XScaleChart::setScaleChartBarBorderColor(const QColor &color)
{
    if(xScalePrivateP->scaleChartBarBorderColor == color)
        return;

    xScalePrivateP->scaleChartBarBorderColor = color;
    this->update();
}

/*!
    \property XScale::scaleChartBarBgColor
    \brief the color of the scaleChartBarBackground

    The default scaleChartBarBgColor is Qt::white.

    \sa indent
*/
QColor XScaleChart::getScaleChartBarBgColor() const
{
    return xScalePrivateP->scaleChartBarBgColor;
}

void XScaleChart::setScaleChartBarBgColor(const QColor &color)
{
    if(xScalePrivateP->scaleChartBarBgColor == color)
        return;

    xScalePrivateP->scaleChartBarBgColor = color;
    this->update();
}

/*!
    \property XScale::scaleChartBarColor
    \brief the color of the scaleChartBar

    The default scaleChartBarColor is Qt::green.

    \sa indent
*/
QColor XScaleChart::getScaleChartBarColor() const
{
    return xScalePrivateP->scaleChartBarColor;
}

void XScaleChart::setScaleChartBarColor(const QColor &color)
{
    if(xScalePrivateP->scaleChartBarColor == color)
        return;

    xScalePrivateP->scaleChartBarColor = color;
    this->update();
}

/*!
    \property XScale::scaleChartBarWarningColor
    \brief the color of the scaleChartBarWarning

    The default scaleChartBarWarningColor is Qt::red.

    \sa indent
*/
QColor XScaleChart::getScaleChartBarWarningColor() const
{
    return xScalePrivateP->scaleChartBarWarningColor;
}

void XScaleChart::setScaleChartBarWarningColor(const QColor &color)
{
    if(xScalePrivateP->scaleChartBarWarningColor == color)
        return;

    xScalePrivateP->scaleChartBarWarningColor = color;
    this->update();
}

/*!
    \property XScale::currentValue
    \brief the currentValue of the scaleChartBar

    The default currentValue is minimumRange.

    \sa indent
*/
double XScaleChart::getCurrentValue() const
{
    return xScalePrivateP->currentValue;
}

void XScaleChart::setCurrentValue(double value)
{
    if(xScalePrivateP->currentValue == value)
        return;

    (value < xScaleP->minimumRange) ? (xScalePrivateP->currentValue = xScaleP->minimumRange) : (xScalePrivateP->currentValue = value);
    (value > xScaleP->maximumRange) ? (xScalePrivateP->currentValue = xScaleP->maximumRange) : (xScalePrivateP->currentValue = value);

    this->update();
}

/*!
    \property XScale::warningValue
    \brief the warningValue of the scaleChartBar

    The default warningValue is maximumRange.

    \sa indent
*/
double XScaleChart::getWarningValue() const
{
    return xScalePrivateP->warningValue;
}

void XScaleChart::setWarningValue(double value)
{
    if(xScalePrivateP->warningValue == value)
        return;

    (value < xScaleP->minimumRange) ? (xScalePrivateP->warningValue = xScaleP->minimumRange) : (xScalePrivateP->warningValue = value);
    (value > xScaleP->maximumRange) ? (xScalePrivateP->warningValue = xScaleP->maximumRange) : (xScalePrivateP->warningValue = value);

    this->update();
}

/*!
    \property XScale::currentValueStringColor
    \brief the color of the currentValueString

    The default currentValueStringColor is Qt::black.

    \sa indent
*/
QColor XScaleChart::getCurrentValueStringColor() const
{
    return xScalePrivateP->currentValueStringColor;
}

void XScaleChart::setCurrentValueStringColor(const QColor &color)
{
    if(xScalePrivateP->currentValueStringColor == color)
        return;

    xScalePrivateP->currentValueStringColor = color;
    this->update();
}


/*!
    \property XScale::currentValueShowEnable
    \brief the enable of the currentValueShow

    The default currentValueShowEnable is true.

    \sa indent
*/
bool XScaleChart::getCurrentValueShowEnable() const
{
    return xScalePrivateP->currentValueShowEnable;
}

void XScaleChart::setCurrentValueShowEnable(bool enable)
{
    if(xScalePrivateP->currentValueShowEnable == enable)
        return;

    xScalePrivateP->currentValueShowEnable = enable;
    this->update();
}

/*!
    \reimp
*/
void XScaleChart::paintEvent(QPaintEvent *ev)
{
    Q_UNUSED(ev);

    //绘制准备工作,启用反锯齿
    QPainter painter(this);
    painter.setRenderHints(QPainter::Antialiasing | QPainter::TextAntialiasing);

    //绘制边框
    drawBorder(&painter);
    //绘制底色
    drawBg(&painter);
    //绘制主题
    drawTitle(&painter);
    //绘制当前值
    drawCurrentValue(&painter);
    //绘制柱状图
    drawBar(&painter);
    //绘制标尺, 不单独显示单位
    setUnitStringEnable(false);
    drawRuler(&painter);
}

/*!
 * \brief XScaleChart::drawTitleString
 * \param painter
 */
void XScaleChart::drawTitle(QPainter *painter)
{
    if(!xScalePrivateP->scaleChartTitleEnable)
    {
        xScalePrivateP->titleWidth = 0;
        xScalePrivateP->titleHeight = 0;
        return;
    }

    painter->save();

    xScalePrivateP->titleWidth = painter->fontMetrics().width(xScalePrivateP->scaleChartTitle);
    xScalePrivateP->titleHeight = painter->fontMetrics().height();

    xScalePrivateP->titlePoint.setX(width() / 2 - xScalePrivateP->titleWidth / 2);
    xScalePrivateP->titlePoint.setY(xScaleP->margin + xScalePrivateP->titleHeight);

    painter->setPen(xScalePrivateP->scaleChartTitleColor);
    painter->drawText(xScalePrivateP->titlePoint, xScalePrivateP->scaleChartTitle);

    painter->restore();
}

/*!
 * \brief XScaleChart::drawCurrentValue
 * \param painter
 */
void XScaleChart::drawCurrentValue(QPainter *painter)
{
    if(!xScalePrivateP->currentValueShowEnable)
    {
        xScalePrivateP->currentValueStringWidth = 0;
        xScalePrivateP->currentValueStringHeight = 0;
        return;
    }

    xScalePrivateP->currentValueString = QString::number(xScalePrivateP->currentValue) + xScaleP->unitString;
    xScalePrivateP->currentValueStringWidth = painter->fontMetrics().width(xScalePrivateP->currentValueString);
    xScalePrivateP->currentValueStringHeight = painter->fontMetrics().height();

    switch(xScaleP->scaleDirection)
    {
    case Face_UP:
    {
        xScalePrivateP->currentValueStringPonit.setX(width() - xScaleP->margin - xScalePrivateP->currentValueStringWidth);
        xScalePrivateP->currentValueStringPonit.setY(height() - height() / 2 - xScalePrivateP->currentValueStringHeight / 2);

        break;
    }
    case Face_Down:
    {
        xScalePrivateP->currentValueStringPonit.setX(width() - xScaleP->margin - xScalePrivateP->currentValueStringWidth);
        xScalePrivateP->currentValueStringPonit.setY(height() - height() / 2 - xScalePrivateP->currentValueStringHeight / 2);

        break;
    }
    case To_Left:
    {
        xScalePrivateP->currentValueStringPonit.setX(width() / 2 - xScalePrivateP->currentValueStringWidth / 2);
        xScalePrivateP->currentValueStringPonit.setY(height() - xScaleP->margin);

        break;
    }
    case To_Right:
    {
        xScalePrivateP->currentValueStringPonit.setX(width() / 2 - xScalePrivateP->currentValueStringWidth / 2);
        xScalePrivateP->currentValueStringPonit.setY(height() - xScaleP->margin);

        break;
    }
    }

    painter->save();

    painter->setPen(xScalePrivateP->currentValueStringColor);
    painter->drawText(xScalePrivateP->currentValueStringPonit, xScalePrivateP->currentValueString);

    painter->restore();
}

/*!
 * \brief XScaleChart::drawBarBg
 * \param painter
 */
void XScaleChart::drawBar(QPainter *painter)
{
    painter->save();

    //获取进度条参数
    QPointF topLeftPoint;
    QPointF bottomRightPoint;
    QPointF warningTopLeftPoint;
    QPointF warningBottomRightPoint;
    //获取进度条参数
    getBarParameters(topLeftPoint, bottomRightPoint, warningTopLeftPoint, warningBottomRightPoint);

    //1. 绘制底色
    painter->setPen(QPen(xScalePrivateP->scaleChartBarBorderColor, 0.4));
    painter->setBrush(xScalePrivateP->scaleChartBarBgColor);

    QRectF bgRect(topLeftPoint, bottomRightPoint);

    painter->drawRoundedRect(bgRect, 5, 5);


    //2. 绘制进度色
    if(xScalePrivateP->currentValue < xScalePrivateP->warningValue)
    {
        painter->setPen(Qt::NoPen);
        painter->setBrush(xScalePrivateP->scaleChartBarColor);
    }
    else
    {
        painter->setPen(Qt::NoPen);
        painter->setBrush(xScalePrivateP->scaleChartBarWarningColor);
    }

    QRectF barRect(warningTopLeftPoint, warningBottomRightPoint);

    painter->drawRoundedRect(barRect, 2, 2);

    painter->restore();
}

/*!
 * \brief XScaleChart::getBarThickness
 */
void XScaleChart::getBarParameters(QPointF &topLeftPoint, QPointF &bottomRightPoint, QPointF &warningTopLeftPoint, QPointF &warningBottomRightPoint)
{
    //分情况求得进度条参数
    switch(xScaleP->scaleDirection)
    {
    case Face_UP:
    {
        xScalePrivateP->barThickness = ((double)height() - 2 * xScaleP->margin - xScalePrivateP->titleHeight - xScaleP->scaleValueHeight - 6) / 3;
        xScalePrivateP->barLength = (double)width() - 2 * xScaleP->margin - xScalePrivateP->currentValueStringWidth - xScaleP->scaleValueWidth;

        topLeftPoint = QPointF(xScaleP->margin + xScaleP->scaleValueWidth / 2, xScaleP->margin + xScalePrivateP->titleHeight + 2);
        bottomRightPoint = QPointF(topLeftPoint.x() + xScalePrivateP->barLength, topLeftPoint.y() + xScalePrivateP->barThickness);

        // 求得当前值条形图长度
        double currentValueBarLength = xScalePrivateP->barLength
                * (xScalePrivateP->currentValue - xScaleP->minimumRange)
                / (xScaleP->maximumRange - xScaleP->minimumRange);
        //根据刻度尺正逆序进行设置
        if(!xScaleP->scaleValueReverseOrder)
        {
            warningTopLeftPoint = topLeftPoint;
            warningBottomRightPoint = QPointF(warningTopLeftPoint.x() + currentValueBarLength, bottomRightPoint.y());
        }
        else
        {
            warningBottomRightPoint = bottomRightPoint;
            warningTopLeftPoint = QPointF(warningBottomRightPoint.x() - currentValueBarLength, topLeftPoint.y());
        }

        break;
    }
    case Face_Down:
    {
        xScalePrivateP->barThickness = ((double)height() - 2 * xScaleP->margin - xScalePrivateP->titleHeight - xScaleP->scaleValueHeight - 6) / 3;
        xScalePrivateP->barLength = (double)width() - 2 * xScaleP->margin - xScalePrivateP->currentValueStringWidth - xScaleP->scaleValueWidth;

        topLeftPoint = QPointF(xScaleP->margin + xScaleP->scaleValueWidth / 2, height() - xScaleP->margin - xScalePrivateP->barThickness);
        bottomRightPoint = QPointF(topLeftPoint.x() + xScalePrivateP->barLength, topLeftPoint.y() + xScalePrivateP->barThickness);

        // 求得当前值条形图长度
        double currentValueBarLength = xScalePrivateP->barLength
                * (xScalePrivateP->currentValue - xScaleP->minimumRange)
                / (xScaleP->maximumRange - xScaleP->minimumRange);
        //根据刻度尺正逆序进行设置
        if(!xScaleP->scaleValueReverseOrder)
        {
            warningTopLeftPoint = topLeftPoint;
            warningBottomRightPoint = QPointF(warningTopLeftPoint.x() + currentValueBarLength, bottomRightPoint.y());
        }
        else
        {
            warningBottomRightPoint = bottomRightPoint;
            warningTopLeftPoint = QPointF(warningBottomRightPoint.x() - currentValueBarLength, topLeftPoint.y());
        }

        break;
    }
    case To_Left:
    {
        xScalePrivateP->barThickness = ((double)width() - 2 * xScaleP->margin  - xScalePrivateP->currentValueStringWidth - 4) / 3;
        xScalePrivateP->barLength = (double)height() - 2 * xScaleP->margin - xScalePrivateP->titleHeight - xScalePrivateP->currentValueStringHeight - xScaleP->scaleValueHeight - 4;

        topLeftPoint = QPointF(xScaleP->margin, xScaleP->margin + xScalePrivateP->titleHeight + xScaleP->scaleValueHeight / 2 + 2);
        bottomRightPoint = QPointF(topLeftPoint.x() + xScalePrivateP->barThickness, topLeftPoint.y() + xScalePrivateP->barLength);

        // 求得当前值条形图长度
        double currentValueBarLength = xScalePrivateP->barLength
                * (xScalePrivateP->currentValue - xScaleP->minimumRange)
                / (xScaleP->maximumRange - xScaleP->minimumRange);
        //根据刻度尺正逆序进行设置
        if(!xScaleP->scaleValueReverseOrder)
        {
            warningTopLeftPoint = topLeftPoint;
            warningBottomRightPoint = QPointF(bottomRightPoint.x(), warningTopLeftPoint.y() + currentValueBarLength);
        }
        else
        {
            warningBottomRightPoint = bottomRightPoint;
            warningTopLeftPoint = QPointF(topLeftPoint.x(), warningBottomRightPoint.y() - currentValueBarLength);
        }

        break;
    }
    case To_Right:
    {
        xScalePrivateP->barThickness = ((double)width() - 2 * xScaleP->margin  - xScalePrivateP->currentValueStringWidth - 4) / 3;
        xScalePrivateP->barLength = (double)height() - 2 * xScaleP->margin - xScalePrivateP->titleHeight - xScalePrivateP->currentValueStringHeight - xScaleP->scaleValueHeight - 4;

        topLeftPoint = QPointF(width() - xScaleP->margin - xScalePrivateP->barThickness, xScaleP->margin + xScalePrivateP->titleHeight + xScaleP->scaleValueHeight / 2 + 2);
        bottomRightPoint = QPointF(topLeftPoint.x() + xScalePrivateP->barThickness, topLeftPoint.y() + xScalePrivateP->barLength);

        // 求得当前值条形图长度
        double currentValueBarLength = xScalePrivateP->barLength
                * (xScalePrivateP->currentValue - xScaleP->minimumRange)
                / (xScaleP->maximumRange - xScaleP->minimumRange);
        //根据刻度尺正逆序进行设置
        if(!xScaleP->scaleValueReverseOrder)
        {
            warningTopLeftPoint = topLeftPoint;
            warningBottomRightPoint = QPointF(bottomRightPoint.x(), warningTopLeftPoint.y() + currentValueBarLength);
        }
        else
        {
            warningBottomRightPoint = bottomRightPoint;
            warningTopLeftPoint = QPointF(topLeftPoint.x(), warningBottomRightPoint.y() - currentValueBarLength);
        }

        break;
    }
    }
}

/*!
 * \brief XScaleChart::getBaseLineParameters
 */
void XScaleChart::getBaseLineParameters()
{
    //分情况求得基线起始点和终止点
    switch(xScaleP->scaleDirection)
    {
    case Face_UP:
    {
        xScaleP->baseLineStartPoint = QPointF(xScaleP->margin + xScaleP->scaleValueWidth / 2, xScalePrivateP->margin + xScalePrivateP->titleHeight + xScalePrivateP->barThickness + 4);
        xScaleP->baseLineEndPoint = QPointF(xScaleP->baseLineStartPoint.x() + xScalePrivateP->barLength, xScaleP->baseLineStartPoint.y());

        xScaleP->baseLineLength = xScaleP->baseLineEndPoint.x() - xScaleP->baseLineStartPoint.x();

        break;
    }
    case Face_Down:
    {
        xScaleP->baseLineStartPoint = QPointF(xScaleP->margin + xScaleP->scaleValueWidth / 2, height() - xScaleP->margin - xScalePrivateP->barThickness - 2);
        xScaleP->baseLineEndPoint = QPointF(xScaleP->baseLineStartPoint.x() + xScalePrivateP->barLength, xScaleP->baseLineStartPoint.y());

        xScaleP->baseLineLength = xScaleP->baseLineEndPoint.x() - xScaleP->baseLineStartPoint.x();

        break;
    }
    case To_Left:
    {
        xScaleP->baseLineStartPoint = QPointF(xScaleP->margin + xScalePrivateP->barThickness + 2, xScaleP->margin + xScalePrivateP->titleHeight + xScaleP->scaleValueHeight / 2 + 2);
        xScaleP->baseLineEndPoint = QPointF(xScaleP->baseLineStartPoint.x(), xScaleP->baseLineStartPoint.y() + xScalePrivateP->barLength);

        xScaleP->baseLineLength = xScaleP->baseLineEndPoint.y() - xScaleP->baseLineStartPoint.y();

        break;
    }
    case To_Right:
    {
        xScaleP->baseLineStartPoint = QPointF(width() - xScaleP->margin - xScalePrivateP->barThickness - 2, xScaleP->margin + xScalePrivateP->titleHeight + xScaleP->scaleValueHeight / 2 + 2);
        xScaleP->baseLineEndPoint = QPointF(xScaleP->baseLineStartPoint.x(),  xScaleP->baseLineStartPoint.y() + xScalePrivateP->barLength);

        xScaleP->baseLineLength = xScaleP->baseLineEndPoint.y() - xScaleP->baseLineStartPoint.y();

        break;
    }
    }
}

/*!
 * \brief XScaleChart::getScaleLineLength
 */
void XScaleChart::getScaleLineLength()
{
    xScaleP->mainScaleLineLength = 2 * xScalePrivateP->barThickness;
    xScaleP->subScaleLineLength = xScaleP->mainScaleLineLength / 2;
}
